package le.cn.nio.server;

import cn.le.util.info.HostInfo;
import com.sun.org.apache.bcel.internal.generic.IF_ACMPEQ;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class NIOEchoServer {

    public static void main(String[] args) throws IOException {
        //1.nio的实现考虑到性能的问题以及相应时间问题,需要设置一个线程池,采用固定大小的线程池
        final ExecutorService executorService = Executors.newFixedThreadPool(10);
        //2.nio的处理是基于channel控制的,所以有一个selector就是负责管理所有的channel
        final ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        //3.设置非阻塞的状态机制
        serverSocketChannel.configureBlocking(false);
        //4.服务器需要提供网络的监听端口
        serverSocketChannel.bind(new InetSocketAddress(HostInfo.PORT));
        //5.设置一个selector,作为一个选择器的出现,目的是管理所有的channel
        Selector selector = Selector.open();
        //6.将当期的channel注册到selector之中
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);//链接处理
        System.out.println("服务器已经启动,服务的监听端口为:" + HostInfo.PORT);
        //7.nio采用轮训的模式,每当发现有用户链接的时候就需要启动一个线程(线程池管理)
        int keySelect = 0; //接受轮训状态
        while ((keySelect = selector.select()) > 0){ //实现轮训处理
            Set<SelectionKey> selectionKeys = selector.selectedKeys();//获取全部的key
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while (iterator.hasNext()){
                SelectionKey selectionKey =  iterator.next();
                if (selectionKey.isAcceptable()){ //为链接模式
                    SocketChannel channelClient = serverSocketChannel.accept();//等待链接
                    channelClient.configureBlocking(false);
                    channelClient.socket().setReuseAddress(true);
                    if (channelClient.finishConnect()){
                        channelClient.register(selector,SelectionKey.OP_READ);
                        System.out.println("注册完成");
                    }
                        //executorService.submit(new EchoClientHandler(channelClient));
                        //serverSocketChannel.register(readeSelector,SelectionKey.OP_READ);
                }
                iterator.remove();;
            }
        }

        executorService.shutdown();
        serverSocketChannel.close();
    }

    private static class EchoClientHandler implements Runnable{
        private SocketChannel clientChannel;
        private boolean flag = true;
        public EchoClientHandler(SocketChannel clientChannel){
            this.clientChannel = clientChannel;
        }

        @Override
        public void run() {
            ByteBuffer byteBuffer = ByteBuffer.allocate(50);
            try {
                while (this.flag){ //需要不断交互
                    byteBuffer.clear();//清空缓冲区
                    int readCount = this.clientChannel.read(byteBuffer);//向缓冲区读取数据
                    if (readCount == 0){
                        continue;
                    }
                    String readMessage = new String(byteBuffer.array(),0,readCount).trim();
                    String writeMessage = "[ECHO] " + readMessage + "\n";
                    if ("bye".equalsIgnoreCase(readMessage)){
                        writeMessage = "[exit] 拜拜";
                        this.flag = false;
                    }
                    //数据输入通过缓存的形式完成,儿数据的输出同样需要进行缓存操作
                    byteBuffer.clear();
                    byteBuffer.put(writeMessage.getBytes());//发送内容
                    byteBuffer.flip(); //重置缓冲区
                    this.clientChannel.write(byteBuffer);//回应数据
                }
            }catch (Exception e){
                e.fillInStackTrace();
            }

        }
    }

}







